import CustomRender from "./CustomRender";

const gfx = cc['gfx'];

let vfmtPosUvColorFront = new gfx.VertexFormat([
    // 节点的世界坐标，占2个float32
    { name: gfx.ATTR_POSITION, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },
    
    // 节点的纹理uv坐标，占2个float32
    // 如果节点使用了独立的纹理（未合图），这里的uv值通常是0或1
    // 合图后的纹理，这里的uv对应其在图集里的相对位置，取值范围在[0,1)内
    { name: gfx.ATTR_UV0, type: gfx.ATTR_TYPE_FLOAT32, num: 2 },

    // 节点颜色值，占4个uint8 = 1个float32
    { name: gfx.ATTR_COLOR, type: gfx.ATTR_TYPE_UINT8, num: 4, normalize: true },
]);

export default class CustomAssembler extends cc.Assembler {
    // 普通四边形的属性，根据实际的顶点格式、数量调整
    protected verticesCount = 4;
    protected indicesCount = 6;
    protected floatsPerVert = 5;

    // vdata offset info
    protected uvOffset = 2;

    protected colorOffset = 4;
    protected renderData: cc.RenderData = null;
    protected _local = null;

    public updateRenderData(comp: any) {
        // if (comp._vertsDirty) {
        //     this.updateUVs(comp);
        //     this.updateColor(comp, null);
        //     comp._vertsDirty = false;
        // }

        if (comp._vertsDirty) {
            this.updateUVs(comp);
            this.updateVerts(comp);
            comp._vertsDirty = false;
        }
    }

    init(comp: cc.RenderComponent) {
        super.init(comp);

        // //@ts-ignore
        // let segmentCount = comp.getPointCount() - 1;
        // this.verticesCount = 4 * segmentCount;
        // this.indicesCount = 6 * segmentCount;
        // this.floatsPerVert = 6;

        this.renderData = new cc.RenderData();
        this.renderData.init(this);
        
        this.initLocal();
        this.initData();
    }

    initLocal() {
        this._local = [];
        this._local.length = 4;
    }

    /** 当前节点的所有顶点数据总大小 */
    get verticesFloats() {
        return this.verticesCount * this.floatsPerVert;
    }

    /**
     * 重载getBuffer(), 默认fillBuffers()方法中会调用到
     * @returns 返回一个能容纳自定义顶点数据的buffer
     */
    getBuffer() {
        //@ts-ignore
        return cc.renderer._handle.getBuffer("mesh", this.getVfmt());
    }

    getVfmt() {
        return vfmtPosUvColorFront;
    }

    updateWorldVerts(comp) {
        if (CC_NATIVERENDERER) {
            this.updateWorldVertsNative(comp);
        } else {
            this.updateWorldVertsWebGL(comp);
        }
    }

    updateWorldVertsWebGL(comp) {
        let local = this._local;
        let verts = this.renderData.vDatas[0];

        let matrix = comp.node._worldMatrix;
        let matrixm = matrix.m,
            a = matrixm[0], b = matrixm[1], c = matrixm[4], d = matrixm[5],
            tx = matrixm[12], ty = matrixm[13];

        let vl = local[0], vr = local[2],
            vb = local[1], vt = local[3];
        
        let justTranslate = a === 1 && b === 0 && c === 0 && d === 1;

        let index = 0;
        let floatsPerVert = this.floatsPerVert;
        if (justTranslate) {
            // left bottom
            verts[index] = vl + tx;
            verts[index+1] = vb + ty;
            index += floatsPerVert;
            // right bottom
            verts[index] = vr + tx;
            verts[index+1] = vb + ty;
            index += floatsPerVert;
            // left top
            verts[index] = vl + tx;
            verts[index+1] = vt + ty;
            index += floatsPerVert;
            // right top
            verts[index] = vr + tx;
            verts[index+1] = vt + ty;
        } else {
            let al = a * vl, ar = a * vr,
            bl = b * vl, br = b * vr,
            cb = c * vb, ct = c * vt,
            db = d * vb, dt = d * vt;

            // left bottom
            verts[index] = al + cb + tx;
            verts[index+1] = bl + db + ty;
            index += floatsPerVert;
            // right bottom
            verts[index] = ar + cb + tx;
            verts[index+1] = br + db + ty;
            index += floatsPerVert;
            // left top
            verts[index] = al + ct + tx;
            verts[index+1] = bl + dt + ty;
            index += floatsPerVert;
            // right top
            verts[index] = ar + ct + tx;
            verts[index+1] = br + dt + ty;
        }
    }

    updateWorldVertsNative(comp) {
        let local = this._local;
        let verts = this.renderData.vDatas[0];
        let floatsPerVert = this.floatsPerVert;
      
        let vl = local[0],
            vr = local[2],
            vb = local[1],
            vt = local[3];
      
        let index = 0;
        // left bottom
        verts[index] = vl;
        verts[index+1] = vb;
        index += floatsPerVert;
        // right bottom
        verts[index] = vr;
        verts[index+1] = vb;
        index += floatsPerVert;
        // left top
        verts[index] = vl;
        verts[index+1] = vt;
        index += floatsPerVert;
        // right top
        verts[index] = vr;
        verts[index+1] = vt;
    }

    updateUVs(sprite) {
        // let uv = [0, 0, 1, 0, 0, 1, 1, 1];

        let uv = [0, 0, 1, 0, 0, 1, 1, 1];
        let uvOffset = this.uvOffset;
        let floatsPerVert = this.floatsPerVert;
        let verts = this.renderData.vDatas[0];

        for (let i = 0; i < 4; i++) {
            let srcOffset = i * 2;
            let dstOffset = floatsPerVert * i + uvOffset;
            verts[dstOffset] = uv[srcOffset];
            verts[dstOffset + 1] = uv[srcOffset + 1];
        }

        // // 获取当前cc.Sprite组件设置的spriteFrame对应的uv
        // // uv数组长度=8，分别表示4个顶点的uv.x, uv.y
        // // 按照左下、右下、左上、右上的顺序存储，注意这里的顺序和顶点索引的数据需要对应上
        // let uv = sprite._spriteFrame.uv;
        // let uvOffset = this.uvOffset;		// 之前提到过vfmtPosUvColor结构里uvOffset = 2
        // let floatsPerVert = this.floatsPerVert; // floatsPerVert = vfmtPosUvColor结构大小 = 5
        // let verts = this.renderData.vDatas[0];
        // for (let i = 0; i < 4; i++) {
        //     // 2个1组取uv数据，写入renderData.vDatas对应位置
        //     let srcOffset = i * 2;
        //     let dstOffset = floatsPerVert * i + uvOffset;
        //     verts[dstOffset] = uv[srcOffset];
        //     verts[dstOffset + 1] = uv[srcOffset + 1];
        // }
    }

    /** 更新颜色 */
    updateColor(comp: any, color: any) {
        let uintVerts = this.renderData.uintVDatas[0];
        if (!uintVerts) return;
        color = color != null ? color : comp.node.color._val;
        let floatsPerVert = this.floatsPerVert;
        let colorOffset = this.colorOffset;
        for (let i = colorOffset, l = uintVerts.length; i < l; i += floatsPerVert) {
            uintVerts[i] = color;
        }
    }

    updateVerts(comp) {
        let node = comp.node,
            cw = node.width,
            ch = node.height,
            appx = node.anchorX * cw,
            appy = node.anchorY * ch,
            l,
            b, 
            r,
            t;

        l = - appx;
        b = - appy;
        r = cw - appx;
        t = ch - appy;

        let local = this._local;
        local[0] = l;
        local[1] = b;
        local[2] = r;
        local[3] = t;
        this.updateWorldVerts(comp);
    }

    updateIsFront(comp, dataOffset) {
        let verts = this.renderData.vDatas[0];
        let index = 0;
        let floatsPerVert = this.floatsPerVert;
        for (let i = 0, n = this.verticesCount; i < n; ++i) {
            index = i * floatsPerVert;
            let isFirstVert = i % 2 === 0;
            let firstVertX = isFirstVert ? verts[index] : verts[index - floatsPerVert];
            let secondVertX = isFirstVert ? verts[index + floatsPerVert] : verts[index];
            let isFront = firstVertX < secondVertX ? 1.0 : 0.0;
            verts[index + dataOffset] = isFront;
        }
    }

    initData() {
        // // this.renderData = new cc.RenderData();
        // // this.renderData.init(this);

        // let data = this.renderData;
        // // createFlexData 支持创建指定格式的 renderData
        // data.createFlexData(0, this.verticesCount, this.indicesCount, this.getVfmt());

        // // createFlexData 不会填充顶点索引信息
        // // 顶点数固定的情况下索引不变化
        // let indices = data.iDatas[0];
        // this.initQuadIndices(indices);

        let data = this.renderData;
        data.createQuadData(0, this.verticesFloats, this.indicesCount);
    }

    /** init quad indices (初始化四边形顶点索引) */
    initQuadIndices(indices: any[]) {
        let count = indices.length / 6;
        for (let i = 0, idx = 0; i < count; i++) {
            let vertextID = i * 4;
            indices[idx++] = vertextID;
            indices[idx++] = vertextID + 1;
            indices[idx++] = vertextID + 2;
            indices[idx++] = vertextID + 1;
            indices[idx++] = vertextID + 3;
            indices[idx++] = vertextID + 2;
        }
    }

    fillBuffers(comp, renderer) {
        let renderData = this.renderData;
        let vData = renderData.vDatas[0];
        let iData = renderData.iDatas[0];

        let buffer = this.getBuffer();
        let offsetInfo = buffer.request(this.verticesCount, this.indicesCount);

        let vertexOffset = offsetInfo.byteOffset >> 2,
            vbuf = buffer._vData;

        if (vData.length + vertexOffset > vbuf.length) {
            vbuf.set(vData.subarray(0, vbuf.length - vertexOffset), vertexOffset);
        } else {
            vbuf.set(vData, vertexOffset);
        }

        let ibuf = buffer._iData,
            indiceOffset = offsetInfo.indiceOffset,
            vertexId = offsetInfo.vertexOffset;
        for (let i = 0, l = iData.length; i < l; i++) {
            ibuf[indiceOffset++] = vertexId + iData[i];
        }
    }
}
